# -*- coding: latin-1 -*-
#=========================================================================================
import atexit
import sqlite3
import collections
import subprocess
import os

import Code.VarGen as VarGen
import Code.ControlPosicion as ControlPosicion
import Code.AperturasStd as AperturasStd
import Code.Movimientos as Movimientos
import Code.Books as Books

import Code.Util as Util

import Code.SQL.DBF as SQLDBF

import Code.QT.QTUtil2 as QTUtil2

#=========================================================================================
class UnMove :
    #--------------------------------------------------------------------------------------------------------------------------------
    def __init__( self, bookGuide, father ) :
        self.bookGuide = bookGuide
        self._rowid = None
        self._father = father
        self._pv = ""
        self._xpv = ""
        self._nag = 0
        self._adv = 0
        self._comment = ""
        self._pos = 0
        self._xdata = {}
        self._graphics = ""
        self._mark = ""

        self._children = []

        self._item = None

        if father :
            self._siBlancas = not father.siBlancas()
            self._numJugada = father.numJugada() + ( 1 if self._siBlancas else 0 )
        else : #root
            self._siBlancas = False
            self._numJugada = 0

        self._fen = ""
        self._pgn = "" # set al crear el pv

        self.readedEXT = False

    #--------------------------------------------------------------------------------------------------------------------------------
    def rowid( self, valor=None ) :
        if valor is not None :
            self._rowid = valor
        return self._rowid

    #--------------------------------------------------------------------------------------------------------------------------------
    def siBlancas( self ) :
        return self._siBlancas

    #--------------------------------------------------------------------------------------------------------------------------------
    def numJugada( self ) :
        return self._numJugada

    #--------------------------------------------------------------------------------------------------------------------------------
    def father( self ) :
        return self._father

    #--------------------------------------------------------------------------------------------------------------------------------
    def pv( self, valor=None ) :
        if valor is not None :
            self._pv = valor
        return self._pv

    #--------------------------------------------------------------------------------------------------------------------------------
    def xpv( self, valor=None ) :
        if valor is not None :
            self._xpv = valor
        return self._xpv

    #--------------------------------------------------------------------------------------------------------------------------------
    def mark( self, valor=None, siLeyendo = False ) :
        if valor is not None :
            ant = self._mark
            self._mark = valor
            if not siLeyendo :
                if ant != valor :
                    self.bookGuide.pteGrabar( self )
                self.bookGuide.actualizaBookmark( self, len(valor) > 0 )
        return self._mark

    #--------------------------------------------------------------------------------------------------------------------------------
    def graphics( self, valor=None, siLeyendo = False ) :
        if valor is None :
            if not self.readedEXT :
                self.readEXT()
        else :
            ant = self._graphics
            self._graphics = valor
            if not siLeyendo and ant != valor :
                self.bookGuide.pteGrabar( self )
        return self._graphics

    #--------------------------------------------------------------------------------------------------------------------------------
    def nag( self, valor=None, siLeyendo = False ) :
        if valor is not None :
            ant = self._nag
            self._nag = valor
            if not siLeyendo and ant != valor :
                self.bookGuide.pteGrabar( self )
        return self._nag

    #--------------------------------------------------------------------------------------------------------------------------------
    def adv( self, valor=None, siLeyendo = False ) :
        if valor is not None :
            ant = self._adv
            self._adv = valor
            if not siLeyendo and ant != valor :
                self.bookGuide.pteGrabar( self )
        return self._adv

    #--------------------------------------------------------------------------------------------------------------------------------
    def comment( self, valor=None, siLeyendo = False ) :
        if valor is None :
            self.readEXT()
        else :
            ant = self._comment
            self._comment = valor
            if not siLeyendo and ant != valor :
                self.bookGuide.pteGrabar( self )
        return self._comment

    #--------------------------------------------------------------------------------------------------------------------------------
    def xdata( self, valor=None, siLeyendo = False ) :
        if valor is None :
            self.readEXT()
        else :
            ant = self._xdata
            self._xdata = valor
            if not siLeyendo and ant != valor:
                self.bookGuide.pteGrabar( self )
            self._xdata = valor
        return self._xdata

    #--------------------------------------------------------------------------------------------------------------------------------
    def pos( self, valor=None, siLeyendo = False ) :
        if valor is not None :
            ant = self._pos
            self._pos = valor
            if not siLeyendo and ant != valor:
                self.bookGuide.pteGrabar( self )
        return self._pos

    #--------------------------------------------------------------------------------------------------------------------------------
    def fen( self, valor=None ) :
        if valor is not None :
            self._fen = valor
            self.bookGuide.setTransposition(self)
        return self._fen
    #--------------------------------------------------------------------------------------------------------------------------------
    def fenM2( self ) :
        fen = self._fen
        sp2 = fen.rfind(" ", 0, fen.rfind(" ") )
        return fen[:sp2]
    #--------------------------------------------------------------------------------------------------------------------------------
    def transpositions( self ) :
        return self.bookGuide.getTranspositions( self )
    #--------------------------------------------------------------------------------------------------------------------------------
    def fenBase( self ) :
        return self._father._fen
    #--------------------------------------------------------------------------------------------------------------------------------
    def pgn( self ) :
        if not self._pgn :
            pv = self._pv
            d,h,c = pv[:2],pv[2:4],pv[4:]
            cp = ControlPosicion.ControlPosicion()
            cp.leeFen(self._father.fen() )
            self._pgn = cp.pgnSP(d,h,c)
            cp.mover( d,h,c )
            self._fen = cp.fen()
        return self._pgn
    #--------------------------------------------------------------------------------------------------------------------------------
    def pgnNum( self ) :
        return "%d.%s%s"%(self._numJugada,"" if self._siBlancas else "..",self.pgn())

    #--------------------------------------------------------------------------------------------------------------------------------
    def item( self, valor=None ) :
        if valor is not None :
            self._item = valor
        return self._item

    #--------------------------------------------------------------------------------------------------------------------------------
    def children( self ) :
        return self._children

    def addChildren( self, move ) :
        self._children.append(move)
        self._children = sorted(self._children, key=lambda uno: uno._pos)

    #--------------------------------------------------------------------------------------------------------------------------------
    def brothers( self ) :
        li = []
        for mv in self._father.children() :
            if mv.pv() != self.pv() :
                li.append(mv)
        return li

    #--------------------------------------------------------------------------------------------------------------------------------
    def analisis( self ) :
        return self.bookGuide.analisisMove(self)

    #--------------------------------------------------------------------------------------------------------------------------------
    def etiPuntos( self ) :
        rm = self.bookGuide.analisisMove(self)
        if rm :
            return rm.abrTextoBase()
        else :
            return ""

    #--------------------------------------------------------------------------------------------------------------------------------
    def historia( self ) :
        li = []
        p = self
        while True :
            li.insert(0,p)
            if not p.father() :
                break
            p = p.father()
        return li

    #--------------------------------------------------------------------------------------------------------------------------------
    def allPV( self ) :
        return Movimientos.xpv2pv(self._xpv)

    #--------------------------------------------------------------------------------------------------------------------------------
    def allPGN( self ) :
        li = []
        for mv in self.historia() :
            if mv._pv :
                if mv.siBlancas() :
                    li.append( "%d."%mv.numJugada() )
                li.append( mv.pgn() )
        return " ".join(li)

    #--------------------------------------------------------------------------------------------------------------------------------
    def readEXT( self ) :
        if self.readedEXT :
            return
        self.readedEXT = True
        self.bookGuide.readEXT( self )

#=========================================================================================
class BookGuide :
    def __init__( self, wowner, nomFichero=None ) :
        if nomFichero is None :
            nomFichero = VarGen.configuracion.ficheroBookGuide

        self.ultPos = 0
        self.dicPtes = {}
        self.nomFichero = nomFichero
        self.conexion = sqlite3.connect( nomFichero )
        self.conexion.text_factory = lambda x: unicode(x, "utf-8", "ignore")
        atexit.register( self.cerrar )

        self.tablaConfig = "CONFIG"

        self.checkInitBook( wowner )

        self.transpositions = {}
        self.bookmarks = []

        self.activeTable = self.getActiveTable()

        self.analisisDB = Util.DicDiskCache( nomFichero, tabla="analisis", maxCache = 1024)

    def reset( self ) :
        self.grabar()
        self.dicPtes = {}
        self.activeTable = self.getActiveTable()
        self.root = UnMove(self, None)
        self.root._fen = ControlPosicion.FEN_INICIAL
        self.readAllDB()

    def readAllDB( self ) :
        self.transpositions = {}
        self.bookmarks = []
        self.ultPos = 0
        select = "ROWID,XPV,PV,NAG,ADV,FEN,MARK,POS"
        orden = "XPV"
        condicion = ""
        dbf = SQLDBF.DBFT( self.conexion, self.activeTable, select, condicion, orden )
        dbf.leer()

        dicMoves = {}
        dicMoves[""] = self.root
        for recno in range(dbf.reccount()) :
            dbf.goto( recno )
            xpv = dbf.XPV
            pv = dbf.PV
            if not pv :
                self.root.rowid( dbf.ROWID )
                continue
            xpvfather = xpv[:-2 if len(pv)==4 else -3]
            if xpvfather in dicMoves :
                father = dicMoves[xpvfather]
                mv = UnMove( self, father )
                mv.pv( pv )
                mv.xpv( xpv )
                mv.fen(dbf.FEN)
                mv.rowid( dbf.ROWID )
                mv.nag( dbf.NAG, True )
                mv.adv( dbf.ADV, True )
                mark = dbf.MARK
                if mark :
                    self.bookmarks.append( mv )
                mv.mark( dbf.MARK, True )
                mv.pos( dbf.POS, True )
                if dbf.POS >= self.ultPos :
                    self.ultPos = dbf.POS
                dicMoves[xpv] = mv
                father.addChildren( mv )

        dbf.cerrar()

    #--------------------------------------------------------------------------------------------------------------------------------
    def listaAnalisis( self, fenM2 ) :
        dic = self.analisisDB[fenM2]
        if dic :
            lista = dic.get( "LISTA", None )
            activo = dic.get( "ACTIVO", None )
        else :
            lista = None
            activo = None
        return lista, activo

    #--------------------------------------------------------------------------------------------------------------------------------
    def analisisMRM( self, fenM2 ) :
        dic = self.analisisDB[fenM2]
        if dic :
            lista = dic.get( "LISTA", None )
            if lista :
                nactive = dic.get("ACTIVO", None)
                if nactive is not None :
                    return lista[nactive]
        return None

    #--------------------------------------------------------------------------------------------------------------------------------
    def analisisMove( self, move ) :
        fenM2 = move.father().fenM2()
        dic = self.analisisDB[fenM2]
        if dic :
            numactivo = dic.get("ACTIVO", None)
            if numactivo is not None:
                lista = dic.get("LISTA",None)
                if lista :
                    if 0 < numactivo >= len(lista) :
                        numactivo = 0
                        dic["ACTIVO"] = 0
                        self.analisisDB[fenM2] = dic
                    analisis = lista[numactivo]
                    if analisis :
                        rm, k = analisis.buscaRM(move.pv())
                        return rm
        return None

    #--------------------------------------------------------------------------------------------------------------------------------
    def getAnalisis( self, fenM2 ) :
        dic = self.analisisDB[fenM2]
        if not dic :
            dic = {"ACTIVO":None, "LISTA":[]}
        return dic
    #--------------------------------------------------------------------------------------------------------------------------------
    def nuevoAnalisis( self, fenM2, analisis ) :
        dic = self.getAnalisis( fenM2 )
        li = dic["LISTA"]
        li.append(analisis)
        dic["ACTIVO"] = len(li)-1
        self.analisisDB[fenM2] = dic

    #--------------------------------------------------------------------------------------------------------------------------------
    def ponAnalisis( self, fenM2, numActivo ) :
        dic = self.getAnalisis( fenM2 )
        dic["ACTIVO"] = numActivo
        self.analisisDB[fenM2] = dic

    #--------------------------------------------------------------------------------------------------------------------------------
    def analisisActivo( self, fenM2 ) :
        dic = self.getAnalisis( fenM2 )
        return dic["ACTIVO"]

    #--------------------------------------------------------------------------------------------------------------------------------
    def quitaAnalisis( self, fenM2, num ) :
        dic = self.getAnalisis( fenM2 )
        li = dic["LISTA"]
        del li[num]
        numActivo = dic["ACTIVO"]
        if numActivo is not None :
            if numActivo == num :
                numActivo = None
            elif numActivo > num :
                numActivo -= 1
        dic["ACTIVO"] = numActivo
        self.analisisDB[fenM2] = dic

    #--------------------------------------------------------------------------------------------------------------------------------
    def setTransposition( self, move ) :
        fenM2 = move.fenM2()
        if fenM2 not in self.transpositions :
            self.transpositions[fenM2] = [move]
        else :
            li = self.transpositions[fenM2]
            if move not in li :
                li.append(move)

    def getTranspositions( self, move ) :
        li = self.transpositions.get(move.fenM2(),[])
        if len(li) <= 1 :
            return []
        n = li.index(move)
        li = li[:]
        del li[n]
        return li
    #--------------------------------------------------------------------------------------------------------------------------------
    def getMovesFenM2( self, fenM2 ) :
        return self.transpositions.get(fenM2, None)

    #--------------------------------------------------------------------------------------------------------------------------------
    def actualizaBookmark( self, move, siPoner ) :
        siEsta = move in self.bookmarks

        if siEsta :
            if not siPoner :
                del self.bookmarks[ self.bookmarks.index(move) ]
        else :
            if siPoner :
                self.bookmarks.append(move)

    #--------------------------------------------------------------------------------------------------------------------------------
    def readEXT( self, move ) :
        select = "COMMENT,GRAPHICS,XDATA"
        condicion = "XPV='%s'"%move.xpv()
        dbf = SQLDBF.DBFT( self.conexion, self.activeTable, select, condicion )
        dbf.leer()
        if dbf.reccount() :
            dbf.goto(0)
            move.comment(dbf.COMMENT, True)
            move.graphics(dbf.GRAPHICS,True)
            move.xdata(Util.blob2var(dbf.XDATA),True)
        dbf.cerrar()

    def pteGrabar( self, move ) :
        huella = move.xpv()
        if huella not in self.dicPtes :
            self.dicPtes[huella] = move
            if len(self.dicPtes) > 5 :
                self.grabar()

    def checkInitBook( self, wowner ) :
        cursor = self.conexion.cursor()
        cursor.execute("pragma table_info(%s)"%self.tablaConfig)
        liCampos = cursor.fetchall()
        cursor.close()
        if not liCampos :
            nactive, activeTable= self.newTable( _("Standard openings") )
            self.grabarSTD(wowner, activeTable)

    def newTable( self, name ) :
        self.grabar()
        dicConf = Util.DicDisk(self.nomFichero,tabla=self.tablaConfig)
        dicL = dicConf["DICLIST"]
        if dicL is None :
            dicL = collections.OrderedDict()
        nActive = 0
        while nActive in dicL :
            nActive += 1

        activeTable = "DATA%d"%nActive
        cursor = self.conexion.cursor()
        sql= "CREATE TABLE %s( XPV TEXT UNIQUE,PV VARCHAR(5),NAG INTEGER,ADV INTEGER,COMMENT TEXT,FEN VARCHAR,MARK VARCHAR, POS INTEGER,GRAPHICS TEXT,XDATA BLOB);"%activeTable
        cursor.execute( sql )
        self.conexion.commit()
        cursor.close()

        dicConf["NUMACTIVE"] = nActive
        dicL[nActive] = name
        dicConf["DICLIST"] = dicL
        dicConf.close()
        return nActive, activeTable

    def copyTable( self, tableFrom, tableTo  ) :
        self.grabar()
        nameFrom = "DATA%d"%tableFrom
        nameTo = "DATA%d"%tableTo
        cursor = self.conexion.cursor()
        sql = "INSERT INTO %s SELECT * FROM %s;"%(nameTo, nameFrom)
        cursor.execute( sql )
        self.conexion.commit()
        cursor.close()

    def mixTable( self, tableFrom, tableTo  ) :
        self.grabar()
        nameFrom = "DATA%d"%tableFrom
        nameTo = "DATA%d"%tableTo
        cursor = self.conexion.cursor()
        cursor.execute( "SELECT ROWID,XPV FROM %s"%nameFrom )
        liValores = cursor.fetchall()
        for rowid,xpv in liValores :
            cursor.execute( 'SELECT ROWID FROM %s WHERE XPV="%s"'%(nameTo,xpv) )
            li = cursor.fetchone()
            if li :
                rowidTo = li[0]
                sql = "DELETE FROM %s WHERE rowid = %d"%( nameTo, rowidTo )
                cursor.execute( sql )
            sql = "INSERT INTO %s SELECT * FROM %s WHERE %s.ROWID = %d;"%(nameTo, nameFrom, nameFrom, rowid)
            cursor.execute( sql )
        self.conexion.commit()
        cursor.close()

    def setActiveTable( self, activeTable ) :
        self.setActiveNumTable( int(activeTable[4:]) )

    def setActiveNumTable( self, nActive ) :
        dicConf = Util.DicDisk(self.nomFichero,tabla=self.tablaConfig)
        dicConf["NUMACTIVE"] = nActive
        dicConf.close()
        self.activeTable = "DATA%d"%nActive

    def remove( self, num ) :
        dicConf = Util.DicDisk(self.nomFichero,tabla=self.tablaConfig)
        dicL = dicConf["DICLIST"]
        del dicL[num]
        dicConf["DICLIST"] = dicL
        dicConf.close()

        table = "DATA%d"%num
        cursor = self.conexion.cursor()
        sql = "DROP TABLE %s;"%table
        cursor.execute( sql )
        sql = "VACUUM;"
        cursor.execute( sql )
        self.conexion.commit()
        cursor.close()

    def rename( self, nTable, newName ) :
        dicConf = Util.DicDisk(self.nomFichero,tabla=self.tablaConfig)
        dicL = dicConf["DICLIST"]
        dicL[nTable] = newName
        dicConf["DICLIST"] = dicL
        dicConf.close()

    def getConfiguration( self ) :
        dicConf = Util.DicDisk(self.nomFichero,tabla=self.tablaConfig)
        active = dicConf["NUMACTIVE"]
        dicL = dicConf["DICLIST"]
        dicConf.close()
        return active, dicL

    def getActiveTable( self ) :
        active, dicL = self.getConfiguration()
        return "DATA%d"%active

    def dataActiveTable( self ) :
        active, dicL = self.getConfiguration()
        return active, dicL[active]

    def grabarFichSTAT( self, fich ) :
        # Para convertir datos de games a bookGuide
        f = open( fich, "rb" )
        liRegs = []
        for linea in f :
            linea = linea.strip()
            xpv, pv, fen = linea.split("|")
            reg = SQLDBF.Almacen()
            reg.XPV = xpv
            reg.PV = pv
            reg.FEN = fen
            self.ultPos += 1
            reg.POS = self.ultPos

            liRegs.append(reg)

        select = "XPV,PV,FEN,POS"
        dbf = SQLDBF.DBFT( self.conexion, self.getActiveTable(), select )
        def dispatch( num ) :
            pass
        dbf.insertarLista(liRegs,dispatch)
        dbf.cerrar()

    def cerrar( self ) :
        if self.conexion  :
            self.conexion.close()
            self.conexion = None
            self.analisisDB.close()

    def grabar( self ) :
        if len(self.dicPtes) == 0 :
            return
        dic = self.dicPtes
        self.dicPtes = {}
        # Creamos una tabla de trabajo
        dbf = SQLDBF.DBF( self.conexion, self.activeTable, "" )
        for k,uno in dic.items() :
            reg = SQLDBF.Almacen()
            reg.XPV = uno.xpv()
            reg.PV = uno.pv()
            reg.NAG = uno.nag()
            reg.ADV = uno.adv()
            reg.COMMENT = uno.comment()
            reg.POS = uno.pos()
            reg.FEN = uno.fen()
            reg.MARK = uno.mark()
            reg.GRAPHICS = uno.graphics()
            reg.XDATA = Util.var2blob(uno.xdata())
            if uno.rowid() is None :
                id = dbf.insertarSoloReg(reg)
                uno.rowid(id)
            else :
                dbf.modificarROWID( uno.rowid(), reg )
        dbf.cerrar()

    def dameMovimiento( self, father, pv ) :
        mv = UnMove( self, father )
        xpv = father.xpv() + Movimientos.pv2xpv(pv)
        mv.xpv( xpv )
        mv.pv( pv )
        cp = ControlPosicion.ControlPosicion()
        cp.leeFen(father.fen())
        cp.moverPV( pv )
        mv.fen(cp.fen())
        self.ultPos += 1
        mv.pos(self.ultPos)
        father.addChildren(mv)
        self.pteGrabar(mv)
        return mv

    def borrar( self, uno ) :

        liBorrados = [uno]

        def allChildren( li, uno ) :
            for x in uno.children() :
                li.append(x.rowid())
                liBorrados.append(x)
                allChildren(li,x)

        liRowid = []
        if uno.rowid() :
            liRowid.append(uno.rowid())
        allChildren(liRowid,uno)
        if liRowid :
            dbf = SQLDBF.DBF( self.conexion, self.activeTable, "" )
            dbf.borrarListaRaw( liRowid )
            if len(liRowid) > 10 :
                dbf.pack()
            dbf.cerrar()

        liQuitarTrasposition = []
        for mov in liBorrados :
            if mov in self.bookmarks :
                del self.bookmarks[self.bookmarks.index(mov)]
            fenM2 = mov.fenM2()
            li = self.transpositions[fenM2]
            if len(li) <= 1 :
                del self.transpositions[fenM2]
            else :
                del li[li.index(mov)]
                if len(li) == 1 :
                    xm = li[0]
                    if xm not in liBorrados :
                        liQuitarTrasposition.append(xm)

        return liBorrados, liQuitarTrasposition

    def allLines( self ) :
        rt = self.root
        liT = []
        def uno(mv) :
            li = mv.children()
            if li :
                for mv in li :
                    uno(mv)
            else :
                liT.append( mv.historia() )
        uno(rt)

        return liT

    def grabarPolyglot( self, ventana, activeTable, ficheroBIN, depth, whiteBest, blackBest ) :

        titulo = _("Import a polyglot book")
        tmpBP2 = QTUtil2.BarraProgreso2( ventana, titulo )
        tmpBP2.ponTotal( 1, 1 )
        tmpBP2.ponRotulo( 1, "1. " + _X( _("Reading %1"), os.path.basename(ficheroBIN) ) )
        tmpBP2.ponTotal( 2, 1 )
        tmpBP2.ponRotulo( 2, "" )
        tmpBP2.mostrar()

        basePos = self.ultPos

        book = Books.Libro( "P", ficheroBIN,ficheroBIN, True )
        book.polyglot()
        cp = ControlPosicion.ControlPosicion()

        lireg = []
        stFenM2 = set() # para que no se produzca un circulo vicioso

        def hazFEN( fen, ply, seq ) :
            plyN = ply+1
            siWhite = " w " in fen
            siMax = False
            if whiteBest :
                siMax = siWhite
            if blackBest :
                siMax = siMax or not siWhite

            liPV = book.miraListaPV( fen, siMax )
            for pv in liPV :
                cp.leeFen( fen )
                cp.mover( pv[:2], pv[2:4], pv[4:] )
                fenN = cp.fen()
                reg = SQLDBF.Almacen()
                lireg.append(reg)
                reg.PV = pv
                seqN = seq + Movimientos.pv2xpv(pv)
                reg.XPV = seqN
                reg.COMMENT = ""
                reg.NAG = 0
                reg.FEN = fenN
                reg.ADV = 0
                self.ultPos += 1
                reg.POS = self.ultPos
                tmpBP2.ponTotal( 1, self.ultPos - basePos )
                tmpBP2.pon( 1, self.ultPos - basePos )
                if plyN < depth :
                    fenM2 = cp.fenM2()
                    if fenM2 not in stFenM2 :
                        stFenM2.add( fenM2 )
                        hazFEN( fenN, plyN, seqN )

        hazFEN( ControlPosicion.FEN_INICIAL, 0, "" )
        select = "XPV,PV,COMMENT,NAG,ADV,FEN,POS"
        dbf = SQLDBF.DBF( self.conexion, activeTable, select )
        tmpBP2.ponTotal( 2, len(lireg) )
        tmpBP2.ponRotulo( 2, _("Writing...") )

        def dispatch( num ) :
            tmpBP2.pon( 2, num )

        dbf.insertarLista(lireg,dispatch)

        dbf.cerrar()
        tmpBP2.cerrar()

    def grabarPGN( self, ventana, activeTable, ficheroPGN, depth ) :

        titulo = _("Import a PGN")
        tmpBP2 = QTUtil2.BarraProgreso2( ventana, titulo )
        tmpBP2.ponTotal( 1, -1 )
        tmpBP2.ponRotulo( 1, "1. " + _X( _("Reading %1"), os.path.basename(ficheroPGN) ) )
        tmpBP2.ponTotal( 2, 1 )
        tmpBP2.ponRotulo( 2, "" )
        tmpBP2.mostrar()

        pgntemp = VarGen.configuracion.ficheroTemporal( "tmp" )
        logtemp = VarGen.configuracion.ficheroTemporal( "log" )
        li = [ os.path.abspath('Engines/Pgn-extract/pgn-extract16-7-changed.exe'),
                ficheroPGN,
                "-o%s"%pgntemp,
                "--nomovenumbers",
                "--noresults",
                "--notags",
                "-Wlalg",
                "-w400000",
                "-bl1",
                "-l%s"%logtemp ]
        process = subprocess.Popen( li, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        process.stdout.read()

        dnag = { "!!":3, "!":1, "?":2, "??":4, "!?":5, "?!":6 }

        def trataLinea( linea ) :
            nlinea = len(linea)
            n = linea.find( "(" )
            while n >= 0 :
                npar = 1
                hasta = nlinea
                for x in range(n+1,nlinea) :
                    c = linea[x]
                    if c == "(" :
                        npar += 1
                    elif c == ")" :
                        npar -= 1
                        if npar == 0 :
                            hasta = x
                            break
                linea1 = linea[:n].strip()+" " + linea[n+1:hasta].strip()
                linea = linea[:n].strip() + " "+linea[hasta+1:].strip()
                trataLinea(linea1)
                nlinea = len(linea)
                n = linea.find( "(" )
            sicom = False
            lireg = []
            lib = linea.split(" ")
            reg = None
            seq = ""
            cp = ControlPosicion.ControlPosicion()
            cp.posInicial()
            for b in lib :
                if b :
                    if sicom :
                        if reg :
                            reg.COMMENT += " " + b
                        sicom = not b.endswith("}")
                        if not sicom :
                            reg.COMMENT = reg.COMMENT[:-1]
                    else :
                        x = b[0]
                        if x in "abcdefgh" :
                            if len(lireg) >= depth :
                                break
                            reg = SQLDBF.Almacen()
                            lireg.append(reg)
                            pv = b.strip("+")
                            cp.mover( pv[:2], pv[2:4], pv[4:])
                            seq += Movimientos.pv2xpv(pv)
                            reg.PV = pv
                            reg.XPV = seq
                            reg.COMMENT = ""
                            reg.FEN = cp.fen()
                            reg.NAG = 0
                            reg.ADV = 0
                        elif x == "$" :
                            t = b[1:]
                            if t.isdigit() :
                                t = int(t)
                                if t in (4,2,1,3,5,6) :
                                    reg.NAG = t
                                elif t in (11,14,15,16,17,18,19) :
                                    reg.ADV = t
                        elif x == "{" :
                            if not reg :
                                reg = SQLDBF.Almacen()
                            reg.COMMENT = b[1:]
                            sicom = not b.endswith("}")
                            if not sicom :
                                reg.COMMENT = reg.COMMENT[:-1]
                        elif b in dnag :
                            reg.NAG = dnag[b]
            for reg in lireg :
                self.ultPos += 1
                reg.POS = self.ultPos
            return lireg

        select = "XPV,PV,COMMENT,NAG,ADV,FEN,POS"
        dbf = SQLDBF.DBF( self.conexion, activeTable, select )

        tm = Util.tamFichero(pgntemp)
        tmpBP2.ponTotal(1, 1)
        tmpBP2.ponTotal( 2, tm )
        tmpBP2.ponRotulo( 2, _("Writing...") )
        f = open(pgntemp)
        t = 0
        for linea in f :
            if tmpBP2.siCancelado() :
                break
            t += len(linea)
            tmpBP2.pon(2, t)
            linea = linea.strip()
            if linea :
                lireg = trataLinea( linea )
                if lireg :
                    dbf.insertarLista(lireg,None)

        f.close()
        dbf.cerrar()
        tmpBP2.cerrar()

    def grabarSTD( self, ventana, activeTable, siBasic = True ) :
        oLista = AperturasStd.ListaAperturasStd(VarGen.configuracion, True, True)
        dic = oLista.dic

        titulo = _("Openings")
        tmpBP2 = QTUtil2.BarraProgreso2( ventana, titulo )
        tf = len(dic)
        tmpBP2.ponTotal( 1, tf )
        tmpBP2.ponRotulo( 1, "1. " + _X( _("Reading %1"), titulo) )
        tmpBP2.ponTotal( 2, tf )
        tmpBP2.ponRotulo( 2, "" )
        tmpBP2.mostrar()

        liRegs = []
        dRegs = {} # se guarda una lista con los pv, para determinar el padre
        for nR, k in enumerate(oLista.dic) :
            tmpBP2.pon( 1, nR )
            tmpBP2.siCancelado()
            ae = oLista.dic[k]
            if siBasic and not ae.siBasic :
                continue
            liPV = ae.a1h8.split(" ")

            ult = len(liPV)-1
            seqFather = ""
            cp = ControlPosicion.ControlPosicion()
            cp.posInicial()
            for pos, pv in enumerate(liPV) :
                desde,hasta,coronacion = pv[:2], pv[2:4], pv[4:]
                seq = seqFather + Movimientos.pv2xpv(pv)
                cp.mover(desde,hasta,coronacion)

                if seq not in dRegs :
                    reg = SQLDBF.Almacen()
                    reg.XPV = seq
                    reg.PV = pv
                    reg.FEN = cp.fen()
                    reg.COMMENT = ae.trNombre if pos == ult else ""
                    self.ultPos += 1
                    reg.POS = self.ultPos

                    liRegs.append(reg)
                    dRegs[seq] = reg

                seqFather = seq

        tmpBP2.ponRotulo( 2, "2. " + _X(_("Converting %1"), titulo) )
        tmpBP2.ponTotal( 2, len(liRegs) )

        select = "XPV,PV,COMMENT,FEN,POS"
        dbf = SQLDBF.DBF( self.conexion, activeTable, select )

        def dispatch( num ) :
            tmpBP2.pon( 2, num )
            tmpBP2.siCancelado()

        dbf.insertarLista(liRegs,dispatch)
        dbf.cerrar()

        tmpBP2.cerrar()
